/*
 * Powered By XY
 * Since 2020
 */

package com.xy.biz.ts.service.impl;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import com.xy.biz.ts.domain.bo.*;
import com.xy.biz.ts.domain.converter.ExaminationPaperConverter;
import com.xy.biz.ts.domain.converter.ExaminationPaperQuestionConverter;
import com.xy.biz.ts.domain.converter.ExaminationQuestionConverter;
import com.xy.biz.ts.domain.query.*;
import com.xy.biz.ts.domain.req.GetExaminationPaperStatusRequest;
import com.xy.biz.ts.domain.req.SaveExaminationPaperQuestionRequest;
import com.xy.biz.ts.domain.req.examinationPaper.GetExaminationPaperRequest;
import com.xy.biz.ts.domain.resp.*;
import com.xy.biz.ts.manager.*;
import com.xy.biz.ts.service.ExaminationPaperRuleService;
import com.xy.tool.context.UserContextHolder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.xy.lang.domain.Result;
import com.xy.biz.ts.service.ExaminationPaperService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

/**
 *
 *
 * @author wcs
 * @date 2021-3-8
 */
@Service
public class ExaminationPaperServiceImpl implements ExaminationPaperService {

    @Autowired
    private ExaminationPaperManager examinationPaperManager;

    @Autowired
    private ExaminationRecordManager examinationRecordManager;

    @Autowired
    private ExaminationPaperQuestionManager examinationPaperQuestionManager;

    @Autowired
    private ExaminationQuestionManager examinationQuestionManager;

    @Autowired
    private ExaminationQuestionOptionManager examinationQuestionOptionManager;

    @Autowired
    private ExaminationPaperRuleService examinationPaperRuleService;

    //固定试题
    @Override
    public Result<?> saveFixedExaminationPaper(ExaminationPaperBO examinationPaperBO) {
        buildFixedExaminationPaperBO(examinationPaperBO);
        int affectedRows = examinationPaperManager.saveExaminationPaper(examinationPaperBO);
        if (affectedRows > 0) {
            return Result.success();
        }

        return Result.ofErrorRowsAffected();
    }

    //随机试题
    @Override
    public Result<?> saveRandomExaminationPaper(ExaminationPaperBO examinationPaperBO) {
        buildRandomExaminationPaperBO(examinationPaperBO);
        int affectedRows = examinationPaperManager.saveExaminationPaper(examinationPaperBO);
        if (affectedRows > 0) {
            return Result.success();
        }
        return Result.ofErrorRowsAffected();
    }


    private void buildRandomExaminationPaperBO(ExaminationPaperBO examinationPaperBO) {
        LocalDateTime now = LocalDateTime.now();
        examinationPaperBO.setType(1); //试卷类型：0-固定试卷，1-随机试卷
        examinationPaperBO.setStatus(1); //状态：0-停用，1-启用
        examinationPaperBO.setTenantId(UserContextHolder.getTenantId());  //租户Id，0表示不指定
        examinationPaperBO.setCreateUserId(UserContextHolder.getUserId()); //创建人Id
        examinationPaperBO.setCreateTime(now);
        examinationPaperBO.setUpdateTime(now);
        examinationPaperBO.setDeleteFlag(false);
    }

    private void buildFixedExaminationPaperBO(ExaminationPaperBO examinationPaperBO) {
        LocalDateTime now = LocalDateTime.now();
        examinationPaperBO.setTotalScore(0); //总分
        examinationPaperBO.setPassScore(0);  //通过分数
        examinationPaperBO.setDuration(0);  //考试时长（分）
        examinationPaperBO.setType(0); //试卷类型：0-固定试卷，1-随机试卷
        examinationPaperBO.setStatus(1); //状态：0-停用，1-启用
        examinationPaperBO.setCover("cover");  //封面
        examinationPaperBO.setNumberOfExamsAllowed(0); //允许考试次数
        examinationPaperBO.setTenantId(UserContextHolder.getTenantId());  //租户Id，0表示不指定
        examinationPaperBO.setCreateUserId(UserContextHolder.getUserId()); //创建人Id
        examinationPaperBO.setCreateTime(now);
        examinationPaperBO.setUpdateTime(now);
    }

    @Override
    public Result<?> saveAllExaminationPaper(Collection<ExaminationPaperBO> collection) {
        int affectedRows = examinationPaperManager.saveAllExaminationPaper(collection);
        if (affectedRows > 0) {
            return Result.success();
        }
        return Result.ofErrorRowsAffected();
    }


    @Override
    public Result<?> saveExaminationPaperRule(Collection<ExaminationPaperRuleBO> examinationPaperBO) {
        examinationPaperBO.stream().forEach(e -> e.setTenantId(UserContextHolder.getTenantId()));
        int affectedRows = examinationPaperManager.saveExaminationPaperRule(examinationPaperBO);
        if (affectedRows > 0) {
            return Result.success();
        }
        return Result.ofErrorRowsAffected();
    }

    @Override
    public Result<?> saveExaminationPaperQuestion(Collection<ExaminationPaperQuestionBO> examinationPaperBO) {
        examinationPaperBO.stream().forEach(e -> e.setTenantId(UserContextHolder.getTenantId()));
        int affectedRows = examinationPaperManager.saveExaminationPaperQuestion(examinationPaperBO);
        if (affectedRows > 0) {
            return Result.success();
        }
        return Result.ofErrorRowsAffected();
    }

    @Transactional
    @Override
    public Result<?> saveExaminationPaperQuestion(ExaminationPaperQuestionBO examinationPaperQuestionBO) {
        ExaminationQuestionBO examinationQuestion = examinationQuestionManager.getExaminationQuestion(examinationPaperQuestionBO.getExaminationQuestionId());
        Integer score = examinationQuestion.getScore();
        ExaminationPaperBO examinationPaperBO = ExaminationPaperBO.builder().examinationPaperId(examinationPaperQuestionBO.getExaminationPaperId()).totalScore(score).build();
        examinationPaperManager.updateExaminationPaper(examinationPaperBO);

        Integer nextSequence = examinationPaperManager.getNextSequence();
        nextSequence = nextSequence == null ? 1 : nextSequence;
        examinationPaperQuestionBO.setSequence(nextSequence);
        examinationPaperQuestionBO.setTenantId(UserContextHolder.getTenantId());
        int affectedRows = examinationPaperManager.saveExaminationPaperQuestion(examinationPaperQuestionBO);
        if (affectedRows > 0) {
            return Result.success();
        }
        return Result.ofErrorRowsAffected();
    }

    @Override
    public Result<?> updateExaminationPaper(ExaminationPaperBO examinationPaperBO) {
        examinationPaperBO.setUpdateTime(LocalDateTime.now());
        int affectedRows = examinationPaperManager.updateExaminationPaper(examinationPaperBO);
        if (affectedRows > 0) {
            return Result.success();
        }
        return Result.ofErrorRowsAffected();
    }

    @Transactional
    @Override
    public Result<?> deleteExaminationPaper(Long examinationPaperId) {
        int affectedRows = examinationPaperManager.deleteExaminationPaper(examinationPaperId);
        if (affectedRows > 0) {
            return Result.success();
        }
        return Result.ofErrorRowsAffected();
    }

    @Override
    public ExaminationPaperBO getExaminationPaper(Long examinationPaperId) {
        return examinationPaperManager.getExaminationPaper(examinationPaperId);
    }

    @Override
    public List<ExaminationPaperBO> listExaminationPaper(ExaminationPaperQuery query) {
        return examinationPaperManager.listExaminationPaper(query);
    }

    @Override
    public int countExaminationPaper(ExaminationPaperQuery query) {
        return examinationPaperManager.countExaminationPaper(query);
    }

    @Override
    public GetExaminationPaperResponse getFixedExaminationPaper(GetExaminationPaperRequest request) {
        if (request.getType() == 0) {
            return examinationPaperManager.getFixedExaminationPaper(request.getExaminationPaperId());
        }
        return null;
    }

    @Override
    public GetExaminationPaperResponse getRandomExaminationPaper(GetExaminationPaperRequest request) {
        if (request.getType() == 1) {
            return examinationPaperManager.getRandomExaminationPaper(request.getExaminationPaperId());
        }
        return null;
    }

    /**
     * 修改状态
     * @param request
     * @return
     */
    @Override
    public Result<?> updateStatusExaminationPaper(GetExaminationPaperStatusRequest request) {
        int affectedRows = examinationPaperManager.updateStatusExaminationPaper(request);
        if (affectedRows > 0) {
            return Result.success();
        }
        return Result.ofErrorRowsAffected();
    }

    /**
     * 删除随机试题
     * @param examinationPaperRuleId
     * @return
     */
    @Override
    public Result<?> deleteRuleExaminationPaper(Long examinationPaperRuleId) {
        int affectedRows = examinationPaperManager.deleteRuleExaminationPaper(examinationPaperRuleId);
        if (affectedRows > 0) {
            return Result.success();
        }
        return Result.ofErrorRowsAffected();
    }

    @Override
    public GetFixedTotalQuestionAndScoreResponse getFixedTotalQuestionAndScore(Long examinationPaperId) {
        ExaminationPaperQuestionQuery query = ExaminationPaperQuestionQuery.max().examinationPaperId(examinationPaperId).build();
        int questionCount = examinationPaperQuestionManager.countExaminationPaperQuestion(query);
        List<ExaminationPaperQuestionBO> examinationPaperQuestionBOS = examinationPaperQuestionManager.listExaminationPaperQuestion(query);
        if (CollectionUtils.isEmpty(examinationPaperQuestionBOS) || questionCount == 0) {
            GetFixedTotalQuestionAndScoreResponse.builder().questionCount(0).totalScore(0).build();
        }
        Set<Long> questionIdSet = examinationPaperQuestionBOS.stream().map(ExaminationPaperQuestionBO::getExaminationQuestionId).collect(Collectors.toSet());
        Map<Long, Integer> scoreMap = examinationQuestionManager.listExaminationQuestionById(questionIdSet).stream()
                .collect(Collectors.toMap(q -> q.getExaminationQuestionId(), q -> q.getScore()));
        int totalScore = 0;
        for (ExaminationPaperQuestionBO bo : examinationPaperQuestionBOS) {
            Integer score = scoreMap.get(bo.getExaminationQuestionId());
            totalScore += score;
        }
        return GetFixedTotalQuestionAndScoreResponse.builder().questionCount(questionCount).totalScore(totalScore).build();
    }

    @Override
    public PreviewExaminationPaperResponse previewExaminationPaper(Long examinationPaperId) {
        ExaminationPaperBO examinationPaper = examinationPaperManager.getExaminationPaper(examinationPaperId);
        Objects.requireNonNull(examinationPaper);
        int currentUserNumberOfExamsAllowed = examinationRecordManager.countExaminationRecord(ExaminationRecordQuery.max()
                .examinationPaperId(examinationPaperId)
                .examineeUserId(UserContextHolder.getUserId())
                .trainId(examinationPaper.getTrainId())
                .build());
        examinationPaper.setCurrentUserNumberOfExamsAllowed(currentUserNumberOfExamsAllowed);
        ExaminationPaperQuestionQuery query = ExaminationPaperQuestionQuery.max().examinationPaperId(examinationPaperId).build();
        List<ExaminationPaperQuestionBO> examinationPaperQuestionBOS = examinationPaperQuestionManager.listExaminationPaperQuestion(query);
        Set<Long> questionIdSet = examinationPaperQuestionBOS.stream().map(ExaminationPaperQuestionBO::getExaminationQuestionId).collect(Collectors.toSet());
        PreviewExaminationPaperResponse build = PreviewExaminationPaperResponse
                .builder()
                .examinationPaperResponse(ExaminationPaperConverter.toResponse(examinationPaper))
                .build();
        if (questionIdSet.size() > 0) {
            List<ExaminationQuestionBO> examinationQuestionBOS1 = examinationQuestionManager.listExaminationQuestionById(questionIdSet);
            if (!CollectionUtils.isEmpty(examinationQuestionBOS1)) {
                List<ExaminationQuestionOptionBO> examinationQuestionOptionBOS = examinationQuestionOptionManager.listExaminationQuestionOption(examinationQuestionBOS1.stream().map(ExaminationQuestionBO::getExaminationQuestionId).collect(Collectors.toList()));
                Map<Long, List<ExaminationQuestionOptionBO>> eqoMap = examinationQuestionOptionBOS.stream().collect(Collectors.groupingBy(ExaminationQuestionOptionBO::getExaminationQuestionId));
                examinationQuestionBOS1.forEach(eq ->
                        eq.setOptions(
                                eqoMap.get(eq.getExaminationQuestionId())
                        )
                );
            }
            Map<Integer, List<ExaminationQuestionBO>> questionTypeMap = examinationQuestionBOS1
                    .stream().collect(Collectors.groupingBy(ExaminationQuestionBO::getType));
            List<Integer> orderedTypeList = new ArrayList<>(questionTypeMap.keySet());
            Collections.sort(orderedTypeList);

            List<PreviewExaminationPaperQuestionTypeGroupResponse> previewExaminationPaperResponses = new ArrayList<>();
            orderedTypeList.forEach(
                    t -> {
                        PreviewExaminationPaperQuestionTypeGroupResponse.PreviewExaminationPaperQuestionTypeGroupResponseBuilder builder1 = PreviewExaminationPaperQuestionTypeGroupResponse.builder();
                        builder1.type(t);
                        List<ExaminationQuestionBO> examinationQuestionBOS = questionTypeMap.get(t);
                        builder1.questionCount(examinationQuestionBOS.size());
                        List<PreviewPaperExaminationQuestionResponse> previewPaperExaminationQuestionResponses = ExaminationQuestionConverter.toPreviewPaperResponse(examinationQuestionBOS);
                        builder1.questionList(previewPaperExaminationQuestionResponses);
                        PreviewExaminationPaperQuestionTypeGroupResponse builded = builder1.build();
                        previewExaminationPaperResponses.add(builded);
                    }
            );
            build.setExaminationPaperQuestionList(previewExaminationPaperResponses);
        }
        return build;
    }

    @Override
    public Result<?> generateRandomExaminationPaper(Long examinationPaperId) {
        List<ExaminationPaperQuestionBO> examinationPaperQuestionBOS = new ArrayList<>();
        ExaminationPaperRuleQuery ruleQuery = ExaminationPaperRuleQuery.max().examinationPaperId(examinationPaperId).build();
        List<ExaminationPaperRuleBO> examinationPaperRuleBOS = examinationPaperRuleService.listExaminationPaperRule(ruleQuery);
        for (ExaminationPaperRuleBO examinationPaperRuleBO : examinationPaperRuleBOS) {
            ExaminationQuestionQuery questionQuery = ExaminationQuestionQuery
                    .max()
                    .category(examinationPaperRuleBO.getQuestionCategory())
                    .type(examinationPaperRuleBO.getQuestionType())
                    .score(examinationPaperRuleBO.getScore())
                    .difficulty(examinationPaperRuleBO.getDifficulty()).build();
            List<ExaminationQuestionBO> examinationQuestionBOS = examinationQuestionManager.listExaminationQuestion(questionQuery);
            Collections.shuffle(examinationQuestionBOS);
            List<ExaminationQuestionBO> examinationQuestionForId = examinationQuestionBOS.subList(0, examinationPaperRuleBO.getCount());
            examinationQuestionForId.stream().map(ExaminationQuestionBO::getExaminationQuestionId).forEach(qID ->
                    examinationPaperQuestionBOS.add(ExaminationPaperQuestionBO.builder().examinationPaperId(examinationPaperId)
                            .examinationQuestionId(qID)
                            .sequence(0)
                            .tenantId(UserContextHolder.getTenantId()).build())
            );

        }
        int affectRow = examinationPaperQuestionManager.saveAllExaminationPaperQuestion(examinationPaperQuestionBOS);
        if (affectRow > 0) {
            return Result.success();
        }
        return Result.ofErrorRowsAffected();
    }

    @Override
    public Result<?> deleteExaminationPaperMultiple(Collection<Long> collection) {
        int row = examinationPaperManager.deleteExaminationPaperMultiple(collection);
        if (row > 0) {
            return Result.success();
        }
        return Result.ofErrorRowsAffected();
    }

    @Override
    public Result<?> deleteExaminationPaperQuestionSingle(ExaminationPaperQuestionBO toBO) {
        ExaminationQuestionBO examinationQuestion = examinationQuestionManager.getExaminationQuestion(toBO.getExaminationQuestionId());
        Integer score = examinationQuestion.getScore();
        ExaminationPaperBO examinationPaper = examinationPaperManager.getExaminationPaper(toBO.getExaminationPaperId());
        if (examinationPaper.getTotalScore() - score < examinationPaper.getPassScore()) {//如果总分小于通过分数
            examinationPaper.setPassScore(examinationPaper.getTotalScore() - score);//将通过分数设置为总分
        }
        examinationPaper.setTotalScore(0 - score);
        examinationPaperManager.updateExaminationPaper(examinationPaper);

        int row = examinationPaperQuestionManager.deleteExaminationPaperQuestionByExaminationPaperId(ExaminationPaperQuestionConverter.toPO(toBO));
        if (row > 0) {
            return Result.success();
        }
        return Result.ofErrorRowsAffected();
    }


}
